// @Author EthanScriptOn
// @Desc
package config_source_loader

import (
	"errors"
	"fmt"
	"gitee.com/fatzeng/srf_switch_basic_components/util"
	"gitee.com/fatzeng/srf_switch_config/config_define"
	"strings"
)

type FileBaseSourceLoader struct {
	*BasicSourceLoader
	*util.FileInformation
	fileExtensionSourceType config_define.ConfigSourceType
	currentLoaderSourceType config_define.ConfigSourceType
}

func GenerateFileBaseSourceLoader(steps ConfigSourceLoaderSteps, currentLoaderSourceType config_define.ConfigSourceType) (*FileBaseSourceLoader, error) {
	if steps == nil {
		return nil, errors.New("steps can not be nil")
	}
	basicLoader, err := GenerateBasicSourceLoader(steps)
	if err != nil {
		return nil, err
	}
	fileBaseSourceLoader := new(FileBaseSourceLoader)
	fileBaseSourceLoader.BasicSourceLoader = basicLoader
	fileBaseSourceLoader.currentLoaderSourceType = currentLoaderSourceType
	return fileBaseSourceLoader, nil
}

func (f *FileBaseSourceLoader) ShouldExecute(interface{}) (bool, error) {
	if err := f.FileInformationIsValid(); err != nil {
		return false, err
	}
	if err := f.FileCanSupport(); err != nil {
		return false, err
	}
	if f.isCyclicalLoading(f.FilePath) {
		return false, fmt.Errorf("%v has already been loaded", f.FilePath)
	}
	return true, nil
}

func (f *FileBaseSourceLoader) SetUpFileInformation() (err error) {
	filePath, err := f.ctx.GetFilePath()
	if err != nil {
		return
	}
	fileInformation, err := util.GenerateFileInformation(filePath)
	if err != nil {
		return err
	}
	f.FileInformation = fileInformation
	return
}

func (f *FileBaseSourceLoader) ReadContent() ([]string, error) {
	return f.LoadFile(f.FilePath)
}

func (f *FileBaseSourceLoader) LoadFile(filePath string) ([]string, error) {
	loadLines, err := util.FileLoad(filePath)
	if err != nil {
		return nil, err
	}
	if len(loadLines) <= 0 {
		return nil, fmt.Errorf("the file [%+v] content is empty", filePath)
	}
	return loadLines, nil
}

func (f *FileBaseSourceLoader) LoadConfigSource() (interface{}, error) {
	sourceLoaderResult := new(SourceLoaderResult)
	sourceLoaderResult.SetConfigSourceType(f.fileExtensionSourceType)
	getFileLines, err := f.ReadContent()
	if err != nil {
		return nil, err
	}
	loadNodes, err := f.BasicSourceLoader.LoadSourceLoaderNodes(getFileLines)
	if err != nil {
		return nil, err
	}
	if err = f.BasicSourceLoader.PerfectSourceLoaderResultWithSegmentInformation(sourceLoaderResult, loadNodes); err != nil {
		return nil, err
	}
	f.TagLoading(f.FilePath)
	return sourceLoaderResult, nil
}

func (f *FileBaseSourceLoader) isCyclicalLoading(filePath string) bool {
	_, ok := f.ctx.GetFileLoadingCache()[filePath]
	return ok
}

func (f *FileBaseSourceLoader) FileInformationIsValid() error {
	if err := f.FileInformation.IsValid(); err != nil {
		return err
	}
	if f.AbsPath != f.FilePath {
		return fmt.Errorf("filePath: [%+v] must be an absolute path ", f.FilePath)
	}
	return nil
}

func (f *FileBaseSourceLoader) FileCanSupport() (err error) {
	if err = f.BasicSourceLoader.CanSupport(f.fileExtensionSourceType); err != nil {
		return err
	}
	if f.currentLoaderSourceType != f.fileExtensionSourceType {
		return fmt.Errorf("file type [%+v] is not supported", f.fileExtensionSourceType)
	}
	return nil
}

func (f *FileBaseSourceLoader) Initialization() (err error) {
	if err = f.SetUpFileInformation(); err != nil {
		return err
	}
	f.fileExtensionSourceType = config_define.ConfigSourceType(strings.TrimPrefix(f.FileInformation.FileType, "."))
	return
}
